import java.util.Set;

/**
 * Represents Binomial Classifier
 * @author alecmgo@gmail.com
 *
 */
public class BinomialClassifier extends BaseClassifier {

  public BinomialClassifier(MessageIterator mi) {
    super(mi);
  }
  
  void adjustCount(MessageFeatures mf, String term) {
    termCount.incrementCount(term, mf.newsgroupNumber, 1);
  }
  
  /**
   * Calculates the binomial conditional probabilities P(t|c) (see pg. 244)
   */
  void calculateConditionalProbabilities() {
    calculateConditionalProbabilitiesWithVocabulary(termCount.keySet());
  }

  /**
   * Calculates conditional probabilities based on vocabulary set
   * @param vocabulary
   */
  void calculateConditionalProbabilitiesWithVocabulary(Set<String> vocabulary) {
    for(String term : vocabulary) {
      for(int newsgroup = 0; newsgroup < newsgroupCount.size(); newsgroup++) {
        double numerator = termCount.getCount(term, newsgroup) + 1;
        double denominator = newsgroupCount.getCount(newsgroup) + 2;
        conditionalProbabilities.setCount(term, newsgroup, numerator / denominator);
      }
    }
  }

  double getScore(MessageFeatures message, int newsgroup) {
    return getScoreWithVocabulary(message, newsgroup, termCount.keySet());
  }
  
  double getScoreWithVocabulary(MessageFeatures message, int newsgroup, Set<String> vocabulary) {
    double score = Math.log(newsgroupPrior.getCount(newsgroup));
    //System.err.println("Prior: " + Math.log(newsgroupPrior.getCount(newsgroup)) + "\t" + "Count: " + newsgroupPrior.getCount(newsgroup));
    //double score = 0.0;
    for(String term : vocabulary) {
      if(message.body.keySet().contains(term)) {
        if(conditionalProbabilities.getCount(term, newsgroup) != 0) {
          score += Math.log(conditionalProbabilities.getCount(term, newsgroup));
        } else {
          //terms unseen before
          score += Math.log(0.5);
        }
        //System.err.println("Prior: " + Math.log(newsgroupPrior.getCount(newsgroup)) + "\t" + "Conditional: " + Math.log(conditionalProbabilities.getCount(term, newsgroup)));
      } else {
        if(conditionalProbabilities.getCount(term, newsgroup) != 0) {
          score += Math.log(1 - conditionalProbabilities.getCount(term, newsgroup));
        } else {
          //terms unseen before
          score += Math.log(0.5);
        }
        //System.err.println("Prior: " + Math.log(newsgroupPrior.getCount(newsgroup)) + "\t" + "Conditional: " + Math.log(1 - conditionalProbabilities.getCount(term, newsgroup)));
      }
    }
    return score;
  }
}